/*
 * Copyright (c) 2016 Cadence Design Systems, Inc.
 * SPDX-License-Identifier: Apache-2.0
 */

/* XTENSA CONTEXT SAVE AND RESTORE ROUTINES
 *
 * Low-level Call0 functions for handling generic context save and restore of
 * registers not specifically addressed by the interrupt vectors and handlers.
 * Those registers (not handled by these functions) are PC, PS, A0, A1 (SP).
 * Except for the calls to RTOS functions, this code is generic to Xtensa.
 *
 * Note that in Call0 ABI, interrupt handlers are expected to preserve the
 * callee-save regs (A12-A15), which is always the case if the handlers are
 * coded in C. However A12, A13 are made available as scratch registers for
 * interrupt dispatch code, so are presumed saved anyway, and are always
 * restored even in Call0 ABI. Only A14, A15 are truly handled as callee-save
 * regs.
 *
 * Because Xtensa is a configurable architecture, this port supports all user
 * generated configurations (except restrictions stated in the release notes).
 * This is accomplished by conditional compilation using macros and functions
 * defined in the Xtensa HAL (hardware adaptation layer) for your
 * configuration. Only the processor state included in your configuration is
 * saved and restored, including any processor state added by user
 * configuration options or TIE.
 */

/*  Warn nicely if this file gets named with a lowercase .s instead of .S:  */
#define NOERROR #
NOERROR: .error "C preprocessor needed for this file: make sure its filename\
 ends in uppercase .S, or use xt-xcc's -x assembler-with-cpp option."


#include "xtensa_rtos.h"

#ifdef XT_USE_OVLY
#include <xtensa/overlay_os_asm.h>
#endif

    .text

/*
 * _xt_context_save
 *
 * !! MUST BE CALLED ONLY BY 'CALL0' INSTRUCTION !!
 *
 * Saves all Xtensa processor state except PC, PS, A0, A1 (SP), A12, A13, in
 * the interrupt stack frame defined in xtensa_rtos.h. Its counterpart is
 * _xt_context_restore (which also restores A12, A13).
 *
 * Caller is expected to have saved PC, PS, A0, A1 (SP), A12, A13 in the frame.
 * This function preserves A12 & A13 in order to provide the caller with 2
 * scratch regs that need not be saved over the call to this function. The
 * choice of which 2 regs to provide is governed by xthal_window_spill_nw and
 * xthal_save_extra_nw, to avoid moving data more than necessary. Caller can
 * assign regs accordingly.
 *
 * Entry Conditions:
 *  A0  = Return address in caller.
 *  A1  = Stack pointer of interrupted thread or handler ("interruptee").
 *  Original A12, A13 have already been saved in the interrupt stack frame.
 *  Other processor state except PC, PS, A0, A1 (SP), A12, A13, is as at the
 *  point of interruption.
 *  If windowed ABI, PS.EXCM = 1 (exceptions disabled).
 *
 * Exit conditions:
 *  A0  = Return address in caller.
 *  A1  = Stack pointer of interrupted thread or handler ("interruptee").
 *  A12, A13 as at entry (preserved).
 *  If windowed ABI, PS.EXCM = 1 (exceptions disabled).
 */

    .global _xt_context_save
    .type   _xt_context_save,@function
    .align  4
_xt_context_save:

    s32i    a2,  sp, XT_STK_a2
    s32i    a3,  sp, XT_STK_a3
    s32i    a4,  sp, XT_STK_a4
    s32i    a5,  sp, XT_STK_a5
    s32i    a6,  sp, XT_STK_a6
    s32i    a7,  sp, XT_STK_a7
    s32i    a8,  sp, XT_STK_a8
    s32i    a9,  sp, XT_STK_a9
    s32i    a10, sp, XT_STK_a10
    s32i    a11, sp, XT_STK_a11

    /* Call0 ABI callee-saved regs a12-15 do not need to be saved here.  a12-13
     * are the caller's responsibility so it can use them as scratch. So only
     * need to save a14-a15 here for Windowed ABI (not Call0).
     */
    #ifndef __XTENSA_CALL0_ABI__
    s32i    a14, sp, XT_STK_a14
    s32i    a15, sp, XT_STK_a15
    #endif

    rsr     a3,  SAR
    s32i    a3,  sp, XT_STK_sar

    #if XCHAL_HAVE_LOOPS
    rsr     a3,  LBEG
    s32i    a3,  sp, XT_STK_lbeg
    rsr     a3,  LEND
    s32i    a3,  sp, XT_STK_lend
    rsr     a3,  LCOUNT
    s32i    a3,  sp, XT_STK_lcount
    #endif

    #if XT_USE_SWPRI
    /* Save virtual priority mask */
    movi    a3,  _xt_vpri_mask
    l32i    a3,  a3, 0
    s32i    a3,  sp, XT_STK_VPRI
    #endif

    #if XCHAL_EXTRA_SA_SIZE > 0 || !defined(__XTENSA_CALL0_ABI__)
    mov     a9,  a0                     /* preserve ret addr */
    #endif

    #ifndef __XTENSA_CALL0_ABI__
    /* To spill the reg windows, temp. need pre-interrupt stack ptr and a4-15.
     * Need to save a9,12,13 temporarily (in frame temps) and recover
     * originals. Interrupts need to be disabled below XCHAL_EXCM_LEVEL and
     * window overflow and underflow exceptions disabled (assured by PS.EXCM ==
     * 1).
     */
    s32i    a12, sp, XT_STK_tmp0        /* temp. save stuff in stack frame */
    s32i    a13, sp, XT_STK_tmp1
    s32i    a9,  sp, XT_STK_tmp2

    /* Save the overlay state if we are supporting overlays. Since we just
     * saved three registers, we can conveniently use them here. Note that as
     * of now, overlays only work for windowed calling ABI.
     */
    #ifdef XT_USE_OVLY
    l32i    a9,  sp, XT_STK_PC          /* recover saved PC */
    _xt_overlay_get_state    a9, a12, a13
    s32i    a9,  sp, XT_STK_OVLY        /* save overlay state */
    #endif

    l32i    a12, sp, XT_STK_a12         /* recover original a9,12,13 */
    l32i    a13, sp, XT_STK_a13
    l32i    a9,  sp, XT_STK_a9
    addi    sp,  sp, XT_STK_FRMSZ       /* restore the interruptee's SP */
    call0   xthal_window_spill_nw       /* preserves only a4,5,8,9,12,13 */
    addi    sp,  sp, -XT_STK_FRMSZ
    l32i    a12, sp, XT_STK_tmp0        /* recover stuff from stack frame */
    l32i    a13, sp, XT_STK_tmp1
    l32i    a9,  sp, XT_STK_tmp2
    #endif

    #if XCHAL_EXTRA_SA_SIZE > 0
    /* NOTE: Normally the xthal_save_extra_nw macro only affects address
     * registers a2-a5. It is theoretically possible for Xtensa processor
     * designers to write TIE that causes more address registers to be
     * affected, but it is generally unlikely. If that ever happens, more
     * registers need to be saved/restored around this macro invocation. Here
     * we assume a9,12,13 are preserved. Future Xtensa tools releases might
     * limit the regs that can be affected.
     */
    addi    a2,  sp, XT_STK_EXTRA       /* where to save it */
    # if XCHAL_EXTRA_SA_ALIGN > 16
    movi    a3, -XCHAL_EXTRA_SA_ALIGN
    and     a2, a2, a3                  /* align dynamically >16 bytes */
    # endif
    call0   xthal_save_extra_nw         /* destroys a0,2,3,4,5 */
    #endif

    #if XCHAL_EXTRA_SA_SIZE > 0 || !defined(__XTENSA_CALL0_ABI__)
    mov     a0, a9                      /* retrieve ret addr */
    #endif

    ret

/*_xt_context_restore
 *
 * !! MUST BE CALLED ONLY BY 'CALL0' INSTRUCTION !!
 *
 * Restores all Xtensa processor state except PC, PS, A0, A1 (SP) (and in Call0
 * ABI, A14, A15 which are preserved by all interrupt handlers) from an
 * interrupt stack frame defined in xtensa_rtos.h. Its counterpart is
 * _xt_context_save (whose caller saved A12, A13).
 *
 * Caller is responsible to restore PC, PS, A0, A1 (SP).
 *
 * Entry Conditions:
 *  A0  = Return address in caller.
 *  A1  = Stack pointer of interrupted thread or handler ("interruptee").
 *
 * Exit conditions:
 *  A0  = Return address in caller.
 *  A1  = Stack pointer of interrupted thread or handler ("interruptee").
 *  Other processor state except PC, PS, A0, A1 (SP), is as at the point
 *  of interruption.
 */

    .global _xt_context_restore
    .type   _xt_context_restore,@function
    .align  4
_xt_context_restore:

    #if XCHAL_EXTRA_SA_SIZE > 0
    /* NOTE: Normally the xthal_restore_extra_nw macro only affects address
     * registers a2-a5. It is theoretically possible for Xtensa processor
     * designers to write TIE that causes more address registers to be
     * affected, but it is generally unlikely. If that ever happens, more
     * registers need to be saved/restored around this macro invocation. Here
     * we only assume a13 is preserved. Future Xtensa tools releases might
     * limit the regs that can be affected.
     */
    mov     a13, a0                     /* preserve ret addr */
    addi    a2,  sp, XT_STK_EXTRA       /* where to find it */
    # if XCHAL_EXTRA_SA_ALIGN > 16
    movi    a3, -XCHAL_EXTRA_SA_ALIGN
    and     a2, a2, a3                  /* align dynamically >16 bytes */
    # endif
    call0   xthal_restore_extra_nw      /* destroys a0,2,3,4,5 */
    mov     a0,  a13                    /* retrieve ret addr */
    #endif

    #if XCHAL_HAVE_LOOPS
    l32i    a2,  sp, XT_STK_lbeg
    l32i    a3,  sp, XT_STK_lend
    wsr     a2,  LBEG
    l32i    a2,  sp, XT_STK_lcount
    wsr     a3,  LEND
    wsr     a2,  LCOUNT
    #endif

    #ifdef XT_USE_OVLY
    /* If we are using overlays, this is a good spot to check if we need to
     * restore an overlay for the incoming task. Here we have a bunch of
     * registers to spare. Note that this step is going to use a few bytes of
     * storage below SP (SP-20 to SP-32) if an overlay is going to be
     * restored.
    */
    l32i    a2,  sp, XT_STK_pc          /* retrieve PC */
    l32i    a3,  sp, XT_STK_ps          /* retrieve PS */
    l32i    a4,  sp, XT_STK_ovly        /* retrieve overlay state */
    l32i    a5,  sp, XT_STK_a1          /* retrieve stack ptr */
    _xt_overlay_check_map    a2, a3, a4, a5, a6
    s32i    a2,  sp, XT_STK_pc          /* save updated PC */
    s32i    a3,  sp, XT_STK_ps          /* save updated PS */
    #endif

    #ifdef XT_USE_SWPRI
    /* Restore virtual interrupt priority and interrupt enable */
    movi    a3,  _xt_intdata
    l32i    a4,  a3, 0                  /* a4 = _xt_intenable */
    l32i    a5,  sp, XT_STK_VPRI        /* a5 = saved _xt_vpri_mask */
    and     a4,  a4, a5
    wsr     a4,  INTENABLE              /* update INTENABLE */
    s32i    a5,  a3, 4                  /* restore _xt_vpri_mask */
    #endif

    l32i    a3,  sp, XT_STK_sar
    l32i    a2,  sp, XT_STK_a2
    wsr     a3,  SAR
    l32i    a3,  sp, XT_STK_a3
    l32i    a4,  sp, XT_STK_a4
    l32i    a5,  sp, XT_STK_a5
    l32i    a6,  sp, XT_STK_a6
    l32i    a7,  sp, XT_STK_a7
    l32i    a8,  sp, XT_STK_a8
    l32i    a9,  sp, XT_STK_a9
    l32i    a10, sp, XT_STK_a10
    l32i    a11, sp, XT_STK_a11

    /*
     * Call0 ABI callee-saved regs a12-15 do not need to be restored here.
     * However a12-13 were saved for scratch before XT_RTOS_INT_ENTER(),
     * so need to be restored anyway, despite being callee-saved in Call0.
     */
    l32i    a12, sp, XT_STK_a12
    l32i    a13, sp, XT_STK_a13
    #ifndef __XTENSA_CALL0_ABI__
    l32i    a14, sp, XT_STK_a14
    l32i    a15, sp, XT_STK_a15
    #endif

    ret


/* _xt_coproc_init
 *
 * Initializes global co-processor management data, setting all co-processors
 * to "unowned". Leaves CPENABLE as it found it (does NOT clear it).
 *
 * Called during initialization of the RTOS, before any threads run.
 *
 * This may be called from normal Xtensa single-threaded application code which
 * might use co-processors. The Xtensa run-time initialization enables all
 * co-processors. They must remain enabled here, else a co-processor exception
 * might occur outside of a thread, which the exception handler doesn't expect.
 *
 * Entry Conditions:
 *  Xtensa single-threaded run-time environment is in effect.
 *  No thread is yet running.
 *
 * Exit conditions:
 *  None.
 *
 * Obeys ABI conventions per prototype:
 *  void _xt_coproc_init(void)
 */

#if XCHAL_CP_NUM > 0

    .global _xt_coproc_init
    .type   _xt_coproc_init,@function
    .align  4
_xt_coproc_init:
    ENTRY0

    /* Initialize thread co-processor ownerships to 0 (unowned). */
    movi    a2, _xt_coproc_owner_sa         /* a2 = base of owner array */
    addi    a3, a2, XCHAL_CP_MAX << 2       /* a3 = top+1 of owner array */
    movi    a4, 0                           /* a4 = 0 (unowned) */
1:  s32i    a4, a2, 0
    addi    a2, a2, 4
    bltu    a2, a3, 1b

    RET0

#endif


/* _xt_coproc_release
 *
 * Releases any and all co-processors owned by a given thread. The thread is
 * identified by it's co-processor state save area defined in xtensa_context.h
 *
 * Must be called before a thread's co-proc save area is deleted to avoid
 * memory corruption when the exception handler tries to save the state.
 * May be called when a thread terminates or completes but does not delete
 * the co-proc save area, to avoid the exception handler having to save the
 * thread's co-proc state before another thread can use it (optimization).
 *
 * Entry Conditions:
 *  A2  = Pointer to base of co-processor state save area.
 *
 * Exit conditions:
 *  None.
 *
 * Obeys ABI conventions per prototype:
 *  void _xt_coproc_release(void * coproc_sa_base)
 */

#if XCHAL_CP_NUM > 0

    .global _xt_coproc_release
    .type   _xt_coproc_release,@function
    .align  4
_xt_coproc_release:
    ENTRY0                                  /* a2 = base of save area */

    movi    a3, _xt_coproc_owner_sa         /* a3 = base of owner array */
    addi    a4, a3, XCHAL_CP_MAX << 2       /* a4 = top+1 of owner array */
    movi    a5, 0                           /* a5 = 0 (unowned) */

    rsil    a6, XCHAL_EXCM_LEVEL            /* lock interrupts */

1:  l32i    a7, a3, 0                       /* a7 = owner at a3 */
    bne     a2, a7, 2f                      /* if (coproc_sa_base == owner) */
    s32i    a5, a3, 0                       /*   owner = unowned */
2:  addi    a3, a3, 1<<2                    /* a3 = next entry in owner array */
    bltu    a3, a4, 1b                      /* repeat until end of array */

3:  wsr     a6, PS                          /* restore interrupts */

    RET0

#endif


/* _xt_coproc_savecs
 *
 * If there is a current thread and it has a coprocessor state save area, then
 * save all callee-saved state into this area. This function is called from the
 * solicited context switch handler. It calls a system-specific function to get
 * the coprocessor save area base address.
 *
 * Entry conditions:
 * - The thread being switched out is still the current thread.
 * - CPENABLE state reflects which coprocessors are active.
 * - Registers have been saved/spilled already.
 *
 * Exit conditions:
 * - All necessary CP callee-saved state has been saved.
 * - Registers a2-a7, a13-a15 have been trashed.
 *
 * Must be called from assembly code only, using CALL0.
 */

#if XCHAL_CP_NUM > 0

    .extern     _xt_coproc_sa_offset   /* external reference */

    .global     _xt_coproc_savecs
    .type       _xt_coproc_savecs,@function
    .align      4
_xt_coproc_savecs:

    /* At entry, CPENABLE should be showing which CPs are enabled. */

    rsr     a2, CPENABLE                /* a2 = which CPs are enabled      */
    beqz    a2, .Ldone                  /* quick exit if none              */
    mov     a14, a0                     /* save return address             */
    call0   XT_RTOS_CP_STATE            /* get address of CP save area     */
    mov     a0, a14                     /* restore return address          */
    beqz    a15, .Ldone                 /* if none then nothing to do      */
    s16i    a2, a15, XT_CP_CS_ST        /* save mask of CPs being stored   */
    movi    a13, _xt_coproc_sa_offset   /* array of CP save offsets        */
    l32i    a15, a15, XT_CP_ASA         /* a15 = base of aligned save area */

#if XCHAL_CP0_SA_SIZE
    bbci.l  a2, 0, 2f                   /* CP 0 not enabled                */
    l32i    a14, a13, 0                 /* a14 = _xt_coproc_sa_offset[0]   */
    add     a3, a14, a15                /* a3 = save area for CP 0         */
    xchal_cp0_store a3, a4, a5, a6, a7 continue=0 ofs=-1 \
	select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
2:
#endif

#if XCHAL_CP1_SA_SIZE
    bbci.l  a2, 1, 2f                   /* CP 1 not enabled                */
    l32i    a14, a13, 4                 /* a14 = _xt_coproc_sa_offset[1]   */
    add     a3, a14, a15                /* a3 = save area for CP 1         */
    xchal_cp1_store a3, a4, a5, a6, a7 continue=0 ofs=-1 \
	select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
2:
#endif

#if XCHAL_CP2_SA_SIZE
    bbci.l  a2, 2, 2f
    l32i    a14, a13, 8
    add     a3, a14, a15
    xchal_cp2_store a3, a4, a5, a6, a7 continue=0 ofs=-1 \
	select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
2:
#endif

#if XCHAL_CP3_SA_SIZE
    bbci.l  a2, 3, 2f
    l32i    a14, a13, 12
    add     a3, a14, a15
    xchal_cp3_store a3, a4, a5, a6, a7 continue=0 ofs=-1 \
	select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
2:
#endif

#if XCHAL_CP4_SA_SIZE
    bbci.l  a2, 4, 2f
    l32i    a14, a13, 16
    add     a3, a14, a15
    xchal_cp4_store a3, a4, a5, a6, a7 continue=0 ofs=-1 \
	select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
2:
#endif

#if XCHAL_CP5_SA_SIZE
    bbci.l  a2, 5, 2f
    l32i    a14, a13, 20
    add     a3, a14, a15
    xchal_cp5_store a3, a4, a5, a6, a7 continue=0 ofs=-1 \
	select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
2:
#endif

#if XCHAL_CP6_SA_SIZE
    bbci.l  a2, 6, 2f
    l32i    a14, a13, 24
    add     a3, a14, a15
    xchal_cp6_store a3, a4, a5, a6, a7 continue=0 ofs=-1 \
	select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
2:
#endif

#if XCHAL_CP7_SA_SIZE
    bbci.l  a2, 7, 2f
    l32i    a14, a13, 28
    add     a3, a14, a15
    xchal_cp7_store a3, a4, a5, a6, a7 continue=0 ofs=-1 \
	select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
2:
#endif

.Ldone:
    ret
#endif


/*
 * _xt_coproc_restorecs
 *
 * Restore any callee-saved coprocessor state for the incoming thread.
 * This function is called from coprocessor exception handling, when giving
 * ownership to a thread that solicited a context switch earlier. It calls a
 * system-specific function to get the coprocessor save area base address.
 *
 * Entry conditions:
 * - The incoming thread is set as the current thread.
 * - CPENABLE is set up correctly for all required coprocessors.
 * - a2 = mask of coprocessors to be restored.
 *
 * Exit conditions:
 * - All necessary CP callee-saved state has been restored.
 * - CPENABLE - unchanged.
 * - Registers a2-a7, a13-a15 have been trashed.
 *
 * Must be called from assembly code only, using CALL0.
 */

#if XCHAL_CP_NUM > 0

    .global     _xt_coproc_restorecs
    .type       _xt_coproc_restorecs,@function
    .align      4
_xt_coproc_restorecs:

    mov     a14, a0                     /* save return address             */
    call0   XT_RTOS_CP_STATE            /* get address of CP save area     */
    mov     a0, a14                     /* restore return address          */
    beqz    a15, .Ldone2                /* if none then nothing to do      */
    l16ui   a3, a15, XT_CP_CS_ST        /* a3 = which CPs have been saved  */
    xor     a3, a3, a2                  /* clear the ones being restored   */
    s32i    a3, a15, XT_CP_CS_ST        /* update saved CP mask            */
    movi    a13, _xt_coproc_sa_offset   /* array of CP save offsets        */
    l32i    a15, a15, XT_CP_ASA         /* a15 = base of aligned save area */

#if XCHAL_CP0_SA_SIZE
    bbci.l  a2, 0, 2f                   /* CP 0 not enabled                */
    l32i    a14, a13, 0                 /* a14 = _xt_coproc_sa_offset[0]   */
    add     a3, a14, a15                /* a3 = save area for CP 0         */
    xchal_cp0_load a3, a4, a5, a6, a7 continue=0 ofs=-1 \
	select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
2:
#endif

#if XCHAL_CP1_SA_SIZE
    bbci.l  a2, 1, 2f                   /* CP 1 not enabled                */
    l32i    a14, a13, 4                 /* a14 = _xt_coproc_sa_offset[1]   */
    add     a3, a14, a15                /* a3 = save area for CP 1         */
    xchal_cp1_load a3, a4, a5, a6, a7 continue=0 ofs=-1 \
	select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
2:
#endif

#if XCHAL_CP2_SA_SIZE
    bbci.l  a2, 2, 2f
    l32i    a14, a13, 8
    add     a3, a14, a15
    xchal_cp2_load a3, a4, a5, a6, a7 continue=0 ofs=-1 \
	select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
2:
#endif

#if XCHAL_CP3_SA_SIZE
    bbci.l  a2, 3, 2f
    l32i    a14, a13, 12
    add     a3, a14, a15
    xchal_cp3_load a3, a4, a5, a6, a7 continue=0 ofs=-1 \
	select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
2:
#endif

#if XCHAL_CP4_SA_SIZE
    bbci.l  a2, 4, 2f
    l32i    a14, a13, 16
    add     a3, a14, a15
    xchal_cp4_load a3, a4, a5, a6, a7 continue=0 ofs=-1 \
	select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
2:
#endif

#if XCHAL_CP5_SA_SIZE
    bbci.l  a2, 5, 2f
    l32i    a14, a13, 20
    add     a3, a14, a15
    xchal_cp5_load a3, a4, a5, a6, a7 continue=0 ofs=-1 \
	select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
2:
#endif

#if XCHAL_CP6_SA_SIZE
    bbci.l  a2, 6, 2f
    l32i    a14, a13, 24
    add     a3, a14, a15
    xchal_cp6_load a3, a4, a5, a6, a7 continue=0 ofs=-1 \
	select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
2:
#endif

#if XCHAL_CP7_SA_SIZE
    bbci.l  a2, 7, 2f
    l32i    a14, a13, 28
    add     a3, a14, a15
    xchal_cp7_load a3, a4, a5, a6, a7 continue=0 ofs=-1 \
	select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL
2:
#endif

.Ldone2:
    ret

#endif

